﻿
namespace DatabaseGroup.SSIS.SourceAdapters.Parser
{
    /// <summary>
    /// Parses a row of data from an input file
    /// </summary>
    internal class RowParser
    {
        /// <summary>
        /// The maximum number of columns a row can have
        /// </summary>
        public const int MaxColumnNumber = 1024;

        private readonly FieldParser _fieldParser;
        
        /// <summary>
        /// Indicates that the column and row delimiter is one and the same
        /// </summary>
        private bool _isSingleColumn;

        /// <summary>
        /// Initializes a new instance of the RowParser class
        /// using the delimiters provided
        /// </summary>
        /// <param name="columnDelimiter">The delimiter to split columns</param>
        /// <param name="rowDelimiter">The delimiter to split rows</param>
        /// <param name="qualifier">The text qualifier to use (escaping delimiters)</param>
        public RowParser(string columnDelimiter, string rowDelimiter, string qualifier)
        {
            ArgumentVerifier.CheckStringArgument(rowDelimiter, "rowDelimiter");

            if (string.IsNullOrEmpty(columnDelimiter))
            {
                _isSingleColumn = true;
                if (string.IsNullOrEmpty(qualifier))
                    _fieldParser = FieldParser.BuildParserWithSingleDelimiter(rowDelimiter);
                else
                    _fieldParser = FieldParser.BuildParserWithSingleDelimiterAndQualifier(rowDelimiter, qualifier);
            }
            else
            {
                if (string.IsNullOrEmpty(qualifier))
                    _fieldParser = FieldParser.BuildParserWithTwoDelimiters(columnDelimiter, rowDelimiter);
                else
                    _fieldParser = FieldParser.BuildParserWithTwoDelimitersAndQualifier(columnDelimiter, rowDelimiter, qualifier);
            }
        }

        /// <summary>
        /// Parses the next row of data from the file
        /// </summary>
        /// <param name="reader">The IFileReader representing the input file</param>
        /// <param name="rowData">The RowData object to be populated</param>
        public void ParseNextRow(IFileReader reader, RowData rowData)
        {
            ArgumentVerifier.CheckObjectArgument(reader, "reader");

            if (rowData != null)
                rowData.ResetRowData();
            
            _fieldParser.ResetParsingState();

            if (_isSingleColumn)
            {
                _fieldParser.ParseNext(reader, rowData);
                if (rowData != null)
                {
                    string columnData = _fieldParser.CurrentText;
                    if (!reader.IsEOF || !string.IsNullOrEmpty(columnData))
                        rowData.AddColumnData(_fieldParser.CurrentText);
                }

                return;
            }
            
            while (!reader.IsEOF && !_fieldParser.RowDelimiterMatch)
            {
                _fieldParser.ParseNext(reader, rowData);

                if (rowData == null)
                    continue;

                string columnData = _fieldParser.CurrentText;
                if (!reader.IsEOF || rowData.ColumnCount > 0 || !string.IsNullOrEmpty(columnData))
                {
                    if (MaxColumnNumber == rowData.ColumnCount)
                        throw new RowColumnNumberOverflow();
                        
                    // Add data if this is not the last and empty row.
                    rowData.AddColumnData(_fieldParser.CurrentText);
                }
            }
        }
    }
}
